package cn.theten52.demo.patterns.design.behavior.interpreter.update3.dict;

import java.util.Map;

// Java 定义Context和表达式解析接口

/**
 * 字典表达式操作类型
 */
enum DictionaryOperator {
    //从Key到Value
    KEY_TO_VALUE,
    //从Value到Key
    VALUE_TO_KEY
}

/**
 * 表示所有表达式的抽象接口
 *
 * @author wangjin
 * @date 2021/1/6
 */
interface Expression {

    /**
     * 计算表达式
     *
     * @param context 上下文
     */
    void evaluate(Context context);
}

class Context {
    private Object key;
    private Object value;
    private DictionaryOperator operator;

    public Object getKey() {
        return key;
    }

    public Object getValue() {
        return value;
    }

    public DictionaryOperator getOperator() {
        return operator;
    }

    /**
     * 因为涉及基于字典的双向操作
     * 所以Key、Value、Operator都不能为空
     */
    public Context setKey(Object key) {
        if (key == null) {
            throw new IllegalArgumentException("key");
        }
        this.key = key;
        return this;
    }

    public Context setValue(Object value) {
        if (value == null) {
            throw new IllegalArgumentException("value");
        }
        this.value = value;
        return this;
    }

    public Context setOperator(DictionaryOperator operator) {
        if (operator == null) {
            throw new IllegalArgumentException("operator");
        }
        this.operator = operator;
        return this;
    }
}

/**
 * 保存字典信息的抽象接口
 * 实际项目中，保存字典信息的形式可以有很多种，例如：
 * -枚举。
 * -配置文件。
 * -参数文件。
 * -资源文件。
 * -数据库。
 * - XML文档。
 * - ……
 */
public interface DictionaryStore {
    /**
     * 更新字典内容
     * 对于基于配置、数据库的Store对象可以通过该方法重新加载相应的缓冲信息
     */
    void refresh();

    /**
     * 根据Context定义的Key/Value及访问方向提取信息
     */
    void find(Context context);
}

/**
 * 针对字典信息的表达式的抽象接口
 */
interface DictionaryExpression extends Expression {
    DictionaryStore getStore();

    DictionaryExpression setStore(DictionaryStore store);
}

class DictionaryExpressionImpl implements DictionaryExpression {

    private DictionaryStore dictionaryStore;

    /**
     * 计算表达式
     *
     * @param context 上下文
     */
    @Override
    public void evaluate(Context context) {

    }

    @Override
    public DictionaryStore getStore() {
        return dictionaryStore;
    }

    @Override
    public DictionaryExpression setStore(DictionaryStore store) {
        this.dictionaryStore = store;
        return this;
    }
}

//Java 具体DictionaryStore类型

/**
 * 基于枚举项的具体DictionaryStore
 * Key是枚举项name() String
 * Value是枚举项的值
 */
class EnumDictionaryStore implements DictionaryStore {

    private Class<? extends Enum> enumType;

    public EnumDictionaryStore setEnumType(Class<? extends Enum> enumType) {
        this.enumType = enumType;
        return this;
    }

    //对于枚举类型暂时用不到
    @Deprecated
    @Override
    public void refresh() {
    }

    @Override
    public void find(Context context) {
        switch (context.getOperator()) {
            case KEY_TO_VALUE:
                //按照name()方式
                //context.setValue(ReflectionHelper.getEnumItem(enumType, context.getKey().toString()));
                break;

            case VALUE_TO_KEY:
                //将枚举项的name()作为Key保存
                context.setKey(((Enum)context.getValue()).name());
                break;
        }
    }
}

/**
 * 基于Map<String,String>的DictionaryStore
 */
class MapDictionaryStore implements DictionaryStore {

    //定义数据内容
    private Map<String, String> data;

    public MapDictionaryStore setData(Map<String, String> data) {
        this.data = data;
        return this;
    }

    //对于Map<String,String>类型暂时用不到
    @Override
    public void refresh() {
    }

    /**
     * 根据字典操作方向进行字符串(value)/枚举值(key)的翻译工作
     * 即便存在不同的Key对应同一个Value的情况，也只返回找到的第一个Key
     */
    @Override
    public void find(Context context) {
        if (data == null) {
            throw new NullPointerException();
        }
        if (data.size() == 0) {
            return;
        }
        switch (context.getOperator()) {
            case KEY_TO_VALUE:
                if (data.containsKey(context.getKey())) {
                    context.setValue(data.get(context.getKey()));
                } else {
                    context.setValue(null);
                }
                break;
            case VALUE_TO_KEY:
                String value = context.getValue().toString();
                for (Map.Entry<String, String> entry : data.entrySet()) {
                    if (entry.getValue().equals(value)) {
                        context.setKey(entry.getKey());
                        return;
                    }
                }
                //找不到匹配的Value
                context.setKey(null);
        }
    }
}